﻿#include "utility.h"
#include "opcode.h"

#include <time.h>
#include <stdlib.h>


#define LOG_TIME_IN_NET
#define eps (1e-4)
/*
包格式
{4bytes: total len}{2bytes: function count}{1bytes: opcode, 15bits: objectid, 1bits: use_cache or set_cache}{data ... }
最开始四个字节交给Network层来管
*/
#define LOG_CALLS_AND_DATA

bool first = true;
float enter_time = 0;
float send_time = 0;

float begin_stamp = 0;
float present_stamp = 0;

extern float lossRate;// = 0.0f;
int loseInt = 0;
int tmpJump = 20;  // set a random jump form 0, [tmpJmp ~ tmpJmp + lostInt] will lead to package loss
// this function will determine whether the package to send or loss
// type define the type of the package, update command will loss along with data, 1 for update command and 0 for normal


bool toSend(int type){
	bool ret = true;
	int random1 = 0;
	loseInt = lossRate * 100;   // random integer is less than lost int, return true
	// get the rate and return the result, about 1%- 2% to loss
	if(type == 0){
		random1 = rand() % 100; // inside 100
		if( random1 >= tmpJump && random1 <= tmpJump + loseInt)
			return false;
		else
			return true;
	}else if(type == 1){
		return true;
	}
}

CommandServer::CommandServer() : func_count(0), size_limit(Max_Buf_Size) {
	cur_ptr = buffer + 6;
	buf_size = 6;

	first = true;
}

CommandServer::CommandServer(int _size_limit) : func_count(0), size_limit(_size_limit) {
	cur_ptr = buffer + 6;
	buf_size = 6;
}

void CommandServer::shut_down() {
	// send the end command
	//发送结束指令
	begin_command(MaxSizeUntilNow_Opcode, 0);
	buf_size = cur_ptr - buffer;
	flush();
}


void CommandServer::start_up() {
	InitSocket();
}

void CommandServer::init() {
	InitAsServer("command_server");

	// initialize the random seed
	srand((unsigned )time(NULL));
}

CommandServer::~CommandServer() {

	Log::log("CommandServer::~CommandServer() called\n");
	recoder.print_info();

	CloseSocket(connect_socket);
	CloseSocket(listen_socket);
	CleanUP();
}

void CommandServer::accept_client() {
	Accept();
}

void CommandServer::print_record() {
	recoder.print_info();
}

void CommandServer::begin_command_use_cache(int op_code, int obj_id) {
	this->op_code = op_code;
	sv_ptr = cur_ptr;
	*( (unsigned char*)cur_ptr ) = op_code;
	*( (unsigned short*)(cur_ptr + 1) ) = (obj_id << 1) + 1;  //1 means use_cache, 0 means set_cache
	cur_ptr += 3;
	func_count++;
}

static double begin_time_t = 0.0;
static double end_time_t = 0.0;
static float end_s_time_n = 0.0, end_s_time_o = 0.0; // EndScene new and old time 
static int call_count = 0;
static int data_count= 0;
int frame = 0;

int index_saved = 0;
int vertex_saved = 0;

double all_data = 0.0;
double saved_data = 0.0;

void CommandServer::begin_command(int op_code, int obj_id) {
	Log::log("CommandServer::begin_command(), op_code=%d, obj_id=%d\n", op_code, obj_id);
#ifdef LOG_TIME_IN_NET
	begin_time_t = GetTickCount();
#endif
	this->op_code = op_code;
	call_count++;


	sv_ptr = cur_ptr;
	*( (unsigned char*)cur_ptr ) = op_code;
	*( (unsigned short*)(cur_ptr + 1) ) = (obj_id << 1) + 0;  //1 means use_cache, 0 means set_cache
	cur_ptr += 3;
	func_count++;
	// record the function count in a single frame and the data size
	if(op_code == EndScene_Opcode){


		// clear
		
		frame++;

		end_s_time_o = end_s_time_n;
		end_s_time_n  =  timeGetTime();
		double interval = end_s_time_n - end_s_time_o;
		Log::log("frame %d: delt time:%f, fps:%f, old time:%f, present time:%f\n", frame,interval, 1000.0/interval,end_s_time_o,end_s_time_n);
#ifdef LOG_CALLS_AND_DATA
		Log::slog("Frame %d :call count:%d, frame data size:%d, index save:%d, vertex save:%d rate:%f\n", frame,call_count, data_count, index_saved, vertex_saved, (index_saved + vertex_saved) * 1.0f / ( data_count + index_saved + vertex_saved));
#endif
		all_data += data_count;
		saved_data +=index_saved+vertex_saved;
		index_saved = 0;
		vertex_saved = 0;
		data_count = 0;
		call_count = 0;
	}
	/////////////////////////////////////////////////////
	//记录present的延迟
	if(op_code == EndScene_Opcode && first) {
		first = false;
		enter_time = timeGetTime();
	}
	/*
	if(op_code == EndScene_Opcode) {
		end_s_time_o = end_s_time_n;
		 end_s_time_n  = GetTickCount();
		 double interval = end_s_time_n - end_s_time_o;
		 Log::slog("frame delt time:%f, fps:%f\n", interval, 1000.0/interval);
	}
	*/
	/////////////////////////////////////////////////////

	if(op_code == BeginScene_Opcode) {
		begin_stamp = timeGetTime();
	}
	else if(op_code == EndScene_Opcode) {
		present_stamp = timeGetTime();
#if 0
		Log::slog("CommandClient::begin_command(), begin_stamp=%.4f, present_stamp=%.4f, del_time=%.4f\n", begin_stamp, present_stamp, present_stamp - begin_stamp);
#endif
	}

}
void CommandServer::end_command_im(){
	//recoder.add_record(op_code,cur_ptr - sv_ptr);
	buf_size = cur_ptr - buffer;

	//send data to client immediately
	memcpy(buffer + 4, &func_count, sizeof(short));
	//Log::log("CommandServer::end_command() sending\n");
	int len1 = 0;
	//if( toSend(

#ifdef SEVER_LOSS_PACKET
	// design the robust mechanism
	if( this->op_code != TransmitTextureData_Opcode && this->op_code != IndexBufferUnlock_Opcode && this->op_code != VertexBufferUnlock_Opcode){
		// the update command should never lose, or the update command should lose together with the following data
		if(toSend(0)){
			len1 = SendPacket();
		}

	}
	else{
		len1 = SendPacket();
	}

#else
	len1 = SendPacket();

#endif

	 //len 1= SendPacket();
	if(len1 <=0){
		Log::slog("send data <=0\n");
	}
	
	//发送之后，重置缓冲区状态
	//reset the buffer after sending
	cur_ptr = buffer + 6;
	func_count = 0;
	buf_size = 6;

	/////////////////////////////////////////////////////
	//¼ÇÂ¼presentµÄÑÓ³Ù
	first = true;
#ifdef LOG_TIME_IN_NET
	data_count += len1;
	end_time_t = GetTickCount();
	double interval = end_time_t-begin_time_t;
	if(interval > eps)
		Log::log("func: %d use time:%f\n", this->op_code, interval);
#endif
}

int CommandServer::flush() {

	memcpy(buffer + 4, &func_count, sizeof(short));

	int len1  = 0;

#ifdef SEVER_LOSS_PACKET
	// design the robust mechanism
	if( this->op_code != TransmitTextureData_Opcode && this->op_code != IndexBufferUnlock_Opcode && this->op_code != VertexBufferUnlock_Opcode){
		// the update command should never lose, or the update command should lose together with the following data
		if(toSend(0)){
			len1 = SendPacket();
		}

	}
	else{
		len1 = SendPacket();
	}

#else
	len1 = SendPacket();

#endif


	 

	//发送之后，重置缓冲区状态
	cur_ptr = buffer + 6;
	func_count = 0;
	buf_size = 6;
	return len1;
}

void CommandServer::end_command() {

	//记录当前这条命令的统计信息
	//recoder.add_record(op_code, cur_ptr - sv_ptr);

	buf_size = cur_ptr - buffer;
	Log::log("CommandServer::end_command() called, func:%d\n", this->op_code);
	if(buf_size >= size_limit) {
		
		int len1 = flush();
		if(len1 <=0){
			Log::slog("send data <=0\n");
		}
		Log::log("send data %d\n",len1);
		data_count += len1;

		/////////////////////////////////////////////////////
		//记录present的延迟
		
		/*first = true;
		send_time = timeGetTime();
		float del_time = send_time - enter_time;
		Log::slog("CommandServer::end_command(), enter_time=%.4f, send_time=%.4f, del_time=%.4f\n", enter_time, send_time, del_time);
		*/
		/////////////////////////////////////////////////////
	}






#ifdef LOG_TIME_IN_NET
	end_time_t = GetTickCount();
	double interval = end_time_t-begin_time_t;
	if(interval > eps)
		Log::log("func: %d use time:%f\n", this->op_code, interval);
#endif
}

void CommandServer::cancel_command() {
#ifdef LOG_TIME_IN_NET
	end_time_t = GetTickCount();
	double interval = end_time_t-begin_time_t;
	if(interval > eps)
		Log::log("func: %d use time:%f\n", this->op_code, interval);
#endif
	cur_ptr = sv_ptr;
	func_count--;
}




/////////////////////////////////////////////////////////////////////////////////////
//CommandClient implementation
CommandClient::CommandClient() : func_count(0) {
	cur_ptr = buffer;

	InitAsClient("command_server");
}

CommandClient::~CommandClient() {
	CloseSocket(connect_socket);
	CleanUP();
}

/*
	如果当前缓存没有函数调用，则调用recvPacket接收函数，否则从缓冲区取
*/
void CommandClient::take_command(int& op_code, int& obj_id, int& use_cache) {
	if(func_count == 0) {
		int len = RecvPacket();

		if(len <= 0) {
			op_code = obj_id = -1;
			return;
		}

		func_count = *( (short*)(buffer + 4) );
		cur_ptr = buffer + 6;
	}

	--func_count;
	op_code = *( (unsigned char*)(cur_ptr) );
	cur_ptr++;

	obj_id = ( *( (unsigned short*)(cur_ptr) )  ) >> 1;
	use_cache = ( *( (unsigned short*)(cur_ptr) ) & 1 );

	cur_ptr += 2;

	/*
	if(op_code == BeginScene_Opcode) {
		begin_stamp = timeGetTime();
	}
	else if(op_code == EndScene_Opcode) {
		present_stamp = timeGetTime();
		//Log::slog("CommandClient::take_command(), begin_stamp=%.4f, present_stamp=%.4f, del_time=%.4f\n", begin_stamp, present_stamp, present_stamp - begin_stamp);
	}
	*/
}


void CommandClient::begin_transaction(){
	cur_ptr = buffer;
	func_count = 0;
	buf_size = 0;
}
void CommandClient::end_transaction(){
	buf_size = cur_ptr - buffer;
	SendPacket();
}

int CommandServer::take_data_from_net(){
	int len = RecvPacket();

	//
	cur_ptr = buffer;
	func_count = 0;

	return len;
}

char* CommandClient::get_cur_ptr(int length) {
	char* ret = cur_ptr;
	cur_ptr += length;
	return ret;
}

char* CommandClient::get_cur_ptr() {
	return cur_ptr;
}


/* construct UnstructuredNet with type
* parameter: type, the type of net instance, 1 for server and 2 for client
*/

UnstructuredNet::UnstructuredNet(int type){
	cur_ptr = buffer;

	if(type == 2);
		//InitAsClient("command_server",type);
	else if(type == 1){
		printf("Create Unstructured Net\n");
		InitAsServer("command_server", type);
	}
}
UnstructuredNet::~UnstructuredNet(){
	//Log::log("UnstructuredNet::~UnstructuredNet() called!\n");
	CloseSocket(connect_socket);
	CloseSocket(listen_socket);
	CleanUP();
}

void UnstructuredNet::ConnectServer(int port){
	InitAsClient("command_server", port);
}
void UnstructuredNet::AcceptClient(int port){
	Accept();
}

void UnstructuredNet::write_int(int data) {

#ifdef USE_VARINT
	Compressor::encode_int(data, cur_ptr);
#else
	*( (int*)(cur_ptr) ) = data;
	cur_ptr += sizeof(int);
#endif
}
void UnstructuredNet::write_uint(UINT data) {
#ifdef USE_VARINT
	Compressor::encode_uint(data, cur_ptr);
#else
	*( (UINT*)(cur_ptr) ) = data;
	cur_ptr += sizeof(UINT);
#endif
}
void UnstructuredNet::write_char(char data) {
	*( (char*)(cur_ptr) ) = data;
	cur_ptr += sizeof(char);
}
void UnstructuredNet::write_uchar(unsigned char data) {
	*( (unsigned char*)(cur_ptr) ) = data;
	cur_ptr += sizeof(unsigned char);
}
void UnstructuredNet::write_float(float data) {
	*( (float*)(cur_ptr) ) = data;
	cur_ptr += sizeof(float);
}
void UnstructuredNet::write_short(short data) {
	*( (short*)(cur_ptr) ) = data;
	cur_ptr += sizeof(short);
}
void UnstructuredNet::write_ushort(USHORT data) {
	*( (USHORT*)(cur_ptr) ) = data;
	cur_ptr += sizeof(USHORT);
}
void UnstructuredNet::write_byte_arr(char* data, int length) {
	memcpy(cur_ptr, data, length);
	cur_ptr += length;
}

int UnstructuredNet::read_int() {
#ifdef USE_VARINT
	int data;
	Compressor::decode_int(cur_ptr, data);
	return data;
#else
	int data = *( (int*)(cur_ptr) );
	cur_ptr += sizeof(int);
	return data;
#endif
}
UINT UnstructuredNet::read_uint() {
#ifdef USE_VARINT
	UINT data;
	Compressor::decode_uint(cur_ptr, data);
	return data;
#else
	UINT data = *( (UINT*)(cur_ptr) );
	cur_ptr += sizeof(UINT);
	return data;
#endif
}
char UnstructuredNet::read_char() {
	char data = *( (char*)(cur_ptr) );
	cur_ptr += sizeof(char);
	return data;
}
UCHAR UnstructuredNet::read_uchar() {
	UCHAR data = *( (UCHAR*)(cur_ptr) );
	cur_ptr += sizeof(UCHAR);
	return data;
}
float UnstructuredNet::read_float() {
	float data = *( (float*)(cur_ptr) );
	cur_ptr += sizeof(float);
	return data;
}
short UnstructuredNet::read_short() {
	short data = *( (short*)(cur_ptr) );
	cur_ptr += sizeof(short);
	return data;
}
USHORT UnstructuredNet::read_ushort() {
	USHORT data = *( (USHORT*)(cur_ptr) );
	cur_ptr += sizeof(USHORT);
	return data;
}
void UnstructuredNet::read_byte_arr(char* dst, int length) {
	memcpy(dst, cur_ptr, length);
	cur_ptr += length;
}
// client begin transaction to start transmit data
void UnstructuredNet::begin_transaction(){
	cur_ptr = buffer+ sizeof(int);
	buf_size = sizeof(int);
}
// client end transaction to acturlly send data
void UnstructuredNet::end_transaction(){
	buf_size = cur_ptr - buffer;
	Log::log("transaction end with data len:%d\n", buf_size);
	SendPacket();
}
// the server will get data from net
int UnstructuredNet::get_data(){
	int len = RecvPacket();
	Log::log("UnstructuredNet::get_data() recv data:%d\n", len);
	cur_ptr = buffer+sizeof(int);
	return len;
}